//***************************************************************************
//   Copyright(c)2020, Xidian University D405.
//           All rights reserved
//
//   File name       :   axi_master_with_outstanding.v
//   Module name     :   axi_master_with_outstanding
//   Author          :   Zhao Yuchen
//   Date            :   2022/05/17
//   Version         :   v12.00
//   Edited by       :   Zhao Yuchen
//---------------------------------------------------------------------------
// Changelog : See axi_master_interface_wrapper.v
// Interface list :
//                AXI Master
//                FIFO Control
//***************************************************************************
//`undef VCS_MODEL
module axi_master_with_outstanding #
(
    //parameter integer AXI_UNALIGN_ADDR_EN  = 1,
	parameter integer AXI_BURST_LEN        = 256,
	parameter integer AXI_ID_WIDTH         = 4,
	parameter integer AXI_ADDR_WIDTH       = 32,
	parameter integer AXI_DATA_WIDTH       = 128,
    parameter integer AXI_LIB_WIDTH        = 13, //Width of Max Transmit Length(in BYTES)
	parameter integer AXI_AWUSER_WIDTH     = 0,
	parameter integer AXI_ARUSER_WIDTH     = 0,
	parameter integer AXI_WUSER_WIDTH      = 0,
	parameter integer AXI_RUSER_WIDTH      = 0,
	parameter integer AXI_BUSER_WIDTH      = 0,
	parameter integer AXI_MAX_INSTR_NUM    = 32 //Max transaction(outstanding) number
)
(
	input  wire                           M_AXI_ACLK_I,      //AXI clock input
	input  wire                           M_AXI_ARESETN_I,   //AXI master rstn input
	//AXI Address Writing ch. signals
	output wire [AXI_ID_WIDTH-1 : 0]      M_AXI_AWID_O,
	output wire [AXI_ADDR_WIDTH-1 : 0]    M_AXI_AWADDR_O,
	output wire [7 : 0]                   M_AXI_AWLEN_O,
	output wire [2 : 0]                   M_AXI_AWSIZE_O,
	output wire [1 : 0]                   M_AXI_AWBURST_O,
	output wire                           M_AXI_AWLOCK_O,
	output wire [3 : 0]                   M_AXI_AWCACHE_O,
	output wire [2 : 0]                   M_AXI_AWPROT_O,
	output wire [3 : 0]                   M_AXI_AWQOS_O,
	output wire [AXI_AWUSER_WIDTH-1 : 0]  M_AXI_AWUSER_O,
	output wire                           M_AXI_AWVALID_O,
	input  wire                           M_AXI_AWREADY_I,
    //AXI Data Writing ch. signals
	output wire [AXI_DATA_WIDTH-1 : 0]    M_AXI_WDATA_O,
	output wire [AXI_DATA_WIDTH/8-1 : 0]  M_AXI_WSTRB_O,
	output wire                           M_AXI_WLAST_O,
	output wire [AXI_WUSER_WIDTH-1 : 0]   M_AXI_WUSER_O,
	output wire                           M_AXI_WVALID_O,
	input  wire                           M_AXI_WREADY_I,
    //AXI write response ch. signals
	input  wire [AXI_ID_WIDTH-1 : 0]      M_AXI_BID_I,
	input  wire [1 : 0]                   M_AXI_BRESP_I,
	input  wire [AXI_BUSER_WIDTH-1 : 0]   M_AXI_BUSER_I,
	input  wire                           M_AXI_BVALID_I,
	output wire                           M_AXI_BREADY_O,
    //AXI write Reading Address ch. signals
	output wire [AXI_ID_WIDTH-1 : 0]      M_AXI_ARID_O,
	output wire [AXI_ADDR_WIDTH-1 : 0]    M_AXI_ARADDR_O,
	output wire [7 : 0]                   M_AXI_ARLEN_O,
	output wire [2 : 0]                   M_AXI_ARSIZE_O,
	output wire [1 : 0]                   M_AXI_ARBURST_O,
	output wire                           M_AXI_ARLOCK_O,
	output wire [3 : 0]                   M_AXI_ARCACHE_O,
	output wire [2 : 0]                   M_AXI_ARPROT_O,
	output wire [3 : 0]                   M_AXI_ARQOS_O,
	output wire [AXI_ARUSER_WIDTH-1 : 0]  M_AXI_ARUSER_O,
	output wire                           M_AXI_ARVALID_O,
	input  wire                           M_AXI_ARREADY_I,
    //AXI Reading Data signals
	input  wire [AXI_ID_WIDTH-1 : 0]      M_AXI_RID_I,
	input  wire [AXI_DATA_WIDTH-1 : 0]    M_AXI_RDATA_I,
	input  wire [1 : 0]                   M_AXI_RRESP_I,
	input  wire                           M_AXI_RLAST_I,
	input  wire [AXI_RUSER_WIDTH-1 : 0]   M_AXI_RUSER_I,
	input  wire                           M_AXI_RVALID_I,
	output wire                           M_AXI_RREADY_O,
	
	
	//******  [External Ports] Wirte Channel  ******//
	input  wire [AXI_ID_WIDTH-1 : 0]      write_id_i,            //write transaction id input
	input  wire [AXI_ADDR_WIDTH-1 : 0]    write_addr_i,          //write transaction address input
	input  wire [AXI_LIB_WIDTH-1 : 0]     write_len_in_byte_i,   //write transaction length(in byte) input
	input  wire                           write_desc_en_i,       //write descriptor enable
	input  wire                           write_desc_type_i,     //0: rxdesc   1:txdesc
	input  wire [AXI_DATA_WIDTH-1 : 0]    write_data_i,          //write data input(from an external TxFIFO)
	output wire                           write_ready_o,         //receive write command ready
	input  wire                           start_write_i,         //start a write transaction(input a write command) use posedge or a pulse input

	output wire                           write_fifo_rd_en_o,    //control the external TxFIFO, fetch data to transmit to AXI slave
	input  wire                           write_fifo_rd_empty_i, //TxFIFO empty signal. (control WVALID low)
	input  wire                           write_fifo_rd_valid_i,
	                                                             //if TxFIFO is empty when AXI master transmitting, it usually cause pause.
	output wire [1 : 0]                   write_data_or_desc_sel_o,  //01:data  10:descriptor 00&11:undefine
	output wire [1 : 0]                   write_desc_fifo_sel_o,
	                                                           
	                                                           
	                                                             
	//******  [External Ports] Read Channel  ******//
	input  wire [AXI_ID_WIDTH-1 : 0]      read_id_i,             //read trasaction id input
	input  wire [AXI_ADDR_WIDTH-1 : 0]    read_addr_i,           //read transaction address input                                              
	input  wire [AXI_LIB_WIDTH-1 : 0]     read_len_in_byte_i,    //read transaction length(in byte) input      
	input  wire                           read_desc_en_i,        //write descriptor enable              
	input  wire                           read_desc_type_i,      //0: rxdesc   1:txdesc
	input  wire                           read_data_10g40g_sel_i,
	output wire [AXI_DATA_WIDTH-1 : 0]    read_data_o,           //read data output(to an external RxFIFO)                                    
	output wire                           read_ready_o,          //receive read command ready                                                  
	input  wire                           start_read_i,          //start a read transaction(input a write command) use posedge or a pulse input
  
	output wire                           read_fifo_wr_en_o,     //control the external RxFIFO, save data received(read) from AXI slave
	input  wire                           read_fifo_wr_full_i,   //RxFIFO full signal. (control RREADY low)
                                                                 //if RxFIFO is full when AXI master receiving(reading), it usually cause pause.
    output wire [1 : 0]                   read_data_or_desc_sel_o,
    output wire [1 : 0]                   read_desc_fifo_sel_o,
    output wire [1 : 0]                   read_data_txfifo_sel_o,
    
	output wire [7 : 0]                   transaction_done_pulse_o, 
	// {read_desc_almost_done, write_desc_almost_done, read_data_almost_done, write_data_almost_done, read_desc_done, write_desc_done, read_data_done, write_data_done};
	output wire [2 : 0]                   debug_state_o,             //01:writing 10:reading 11:write&read 00:idle
    input  wire [9 : 0]                   ram_2p_cfg_register,
    input  wire [6 : 0]                   rf_2p_cfg_register
);

    //parameter of write channel FSM state
    localparam  W_IDLE        = 6'b000001;
    localparam  W_FETCH_INSTR = 6'b000010;
    localparam  W_WADDR       = 6'b000100;
    localparam  W_WDATA       = 6'b001000;
    localparam  W_CHKID       = 6'b010000;
    localparam  W_PAUSE       = 6'b100000;
    
    //parameter of read channel FSM state
    localparam  R_IDLE        = 6'b000001;
    localparam  R_FETCH_INSTR = 6'b000010;
    localparam  R_WADDR       = 6'b000100;
    localparam  R_WDATA       = 6'b001000;
    localparam  R_CHKID       = 6'b010000;
    localparam  R_PAUSE       = 6'b100000;
    
    wire                            read_desc_done;
    wire                            write_desc_done;
    wire                            read_data_done;
    wire                            write_data_done;
    wire [5 : 0]                    write_fsm_state;
    wire [5 : 0]                    read_fsm_state;
    wire                            write_data_almost_done;
    wire                            write_desc_almost_done;
    wire                            read_data_almost_done;
    wire                            read_desc_almost_done;
    wire                            write_active_total;
    
    assign transaction_done_pulse_o = {read_desc_almost_done, write_desc_almost_done, read_data_almost_done, write_data_almost_done, read_desc_done, write_desc_done, read_data_done, write_data_done};
    assign debug_state_o            = {write_active_total, ((read_fsm_state != R_IDLE) ? 1'b1 : 1'b0), ((write_fsm_state != W_IDLE) ? 1'b1 : 1'b0)};
    
    axi_master_write_channel_fsm #
    (
        //.AXI_UNALIGN_ADDR_EN     (AXI_UNALIGN_ADDR_EN),
        .AXI_BURST_LEN           (AXI_BURST_LEN),
		.AXI_ID_WIDTH            (AXI_ID_WIDTH),
		.AXI_ADDR_WIDTH          (AXI_ADDR_WIDTH),
		.AXI_DATA_WIDTH          (AXI_DATA_WIDTH),
		.AXI_LIB_WIDTH           (AXI_LIB_WIDTH),
		.AXI_AWUSER_WIDTH        (AXI_AWUSER_WIDTH),
		.AXI_ARUSER_WIDTH        (AXI_ARUSER_WIDTH),
		.AXI_WUSER_WIDTH         (AXI_WUSER_WIDTH),
		.AXI_RUSER_WIDTH         (AXI_RUSER_WIDTH),
		.AXI_BUSER_WIDTH         (AXI_BUSER_WIDTH),
		.AXI_MAX_INSTR_NUM       (AXI_MAX_INSTR_NUM)
    )
    axi_master_write_channel_fsm_inst
    ( 
        .M_AXI_ACLK_I                 (M_AXI_ACLK_I      ),
        .M_AXI_ARESETN_I              (M_AXI_ARESETN_I   ),
        .M_AXI_AWID_O                 (M_AXI_AWID_O      ),
        .M_AXI_AWADDR_O               (M_AXI_AWADDR_O    ),
        .M_AXI_AWLEN_O                (M_AXI_AWLEN_O     ),
        .M_AXI_AWSIZE_O               (M_AXI_AWSIZE_O    ),
        .M_AXI_AWBURST_O              (M_AXI_AWBURST_O   ),
        .M_AXI_AWLOCK_O               (M_AXI_AWLOCK_O    ),
        .M_AXI_AWCACHE_O              (M_AXI_AWCACHE_O   ),
        .M_AXI_AWPROT_O               (M_AXI_AWPROT_O    ),
        .M_AXI_AWQOS_O                (M_AXI_AWQOS_O     ),
        .M_AXI_AWUSER_O               (M_AXI_AWUSER_O    ),
        .M_AXI_AWVALID_O              (M_AXI_AWVALID_O   ),
        .M_AXI_AWREADY_I              (M_AXI_AWREADY_I   ),
        .M_AXI_WDATA_O                (M_AXI_WDATA_O     ),
        .M_AXI_WSTRB_O                (M_AXI_WSTRB_O     ),
        .M_AXI_WLAST_O                (M_AXI_WLAST_O     ),
        .M_AXI_WUSER_O                (M_AXI_WUSER_O     ),
        .M_AXI_WVALID_O               (M_AXI_WVALID_O    ),
        .M_AXI_WREADY_I               (M_AXI_WREADY_I    ),
        .M_AXI_BID_I                  (M_AXI_BID_I       ),
        .M_AXI_BRESP_I                (M_AXI_BRESP_I     ),
        .M_AXI_BUSER_I                (M_AXI_BUSER_I     ),
        .M_AXI_BVALID_I               (M_AXI_BVALID_I    ),
        .M_AXI_BREADY_O               (M_AXI_BREADY_O    ),
        
        .write_id_i                   (write_id_i         ),
		.write_addr_i                 (write_addr_i       ),
		.write_len_in_byte_i          (write_len_in_byte_i),
		.write_desc_en_i              (write_desc_en_i    ),
		.write_desc_type_i            (write_desc_type_i  ),
		.write_data_i                 (write_data_i       ),
		.start_write_i                (start_write_i      ),
		.write_ready_o                (write_ready_o      ),
		
		.write_fifo_rd_en_o           (write_fifo_rd_en_o   ),
		.write_fifo_rd_empty_i        (write_fifo_rd_empty_i),
		.write_fifo_rd_valid_i        (write_fifo_rd_valid_i),
		
		.write_data_or_desc_sel_o     (write_data_or_desc_sel_o ),
		.write_desc_fifo_sel_o        (write_desc_fifo_sel_o),
		
		.write_data_done_o            (write_data_done),
		.write_desc_done_o            (write_desc_done),
		.write_data_almost_done_o     (write_data_almost_done),
		.write_desc_almost_done_o     (write_desc_almost_done),
		.write_fsm_state_o            (write_fsm_state),
		.write_active_total_o         (write_active_total)
`ifndef VCS_MODEL
		,.ram_2p_cfg_register					(ram_2p_cfg_register),
		.rf_2p_cfg_register						(rf_2p_cfg_register)
`endif
    );
    
    
    axi_master_read_channel_fsm #
    (
        //.AXI_UNALIGN_ADDR_EN     (AXI_UNALIGN_ADDR_EN),
        .AXI_BURST_LEN           (AXI_BURST_LEN),
		.AXI_ID_WIDTH            (AXI_ID_WIDTH),
		.AXI_ADDR_WIDTH          (AXI_ADDR_WIDTH),
		.AXI_DATA_WIDTH          (AXI_DATA_WIDTH),
		.AXI_LIB_WIDTH           (AXI_LIB_WIDTH),
		.AXI_AWUSER_WIDTH        (AXI_AWUSER_WIDTH),
		.AXI_ARUSER_WIDTH        (AXI_ARUSER_WIDTH),
		.AXI_WUSER_WIDTH         (AXI_WUSER_WIDTH),
		.AXI_RUSER_WIDTH         (AXI_RUSER_WIDTH),
		.AXI_BUSER_WIDTH         (AXI_BUSER_WIDTH),
		.AXI_MAX_INSTR_NUM       (AXI_MAX_INSTR_NUM)
    )
    axi_master_read_channel_fsm_inst
    (
        .M_AXI_ACLK_I            (M_AXI_ACLK_I    ),
        .M_AXI_ARESETN_I         (M_AXI_ARESETN_I ),
        .M_AXI_ARID_O            (M_AXI_ARID_O    ),
        .M_AXI_ARADDR_O          (M_AXI_ARADDR_O  ),
        .M_AXI_ARLEN_O           (M_AXI_ARLEN_O   ),
        .M_AXI_ARSIZE_O          (M_AXI_ARSIZE_O  ),
        .M_AXI_ARBURST_O         (M_AXI_ARBURST_O ),
        .M_AXI_ARLOCK_O          (M_AXI_ARLOCK_O  ),
        .M_AXI_ARCACHE_O         (M_AXI_ARCACHE_O ),
        .M_AXI_ARPROT_O          (M_AXI_ARPROT_O  ),
        .M_AXI_ARQOS_O           (M_AXI_ARQOS_O   ),
        .M_AXI_ARUSER_O          (M_AXI_ARUSER_O  ),
        .M_AXI_ARVALID_O         (M_AXI_ARVALID_O ),
        .M_AXI_ARREADY_I         (M_AXI_ARREADY_I ),
        .M_AXI_RID_I             (M_AXI_RID_I     ),
        .M_AXI_RDATA_I           (M_AXI_RDATA_I   ),
        .M_AXI_RRESP_I           (M_AXI_RRESP_I   ),
        .M_AXI_RLAST_I           (M_AXI_RLAST_I   ),
        .M_AXI_RUSER_I           (M_AXI_RUSER_I   ),
        .M_AXI_RVALID_I          (M_AXI_RVALID_I  ),
        .M_AXI_RREADY_O          (M_AXI_RREADY_O  ),
        
        .read_id_i               (read_id_i         ),
		.read_addr_i             (read_addr_i       ),
		.read_len_in_byte_i      (read_len_in_byte_i),
		.read_data_10g40g_sel_i  (read_data_10g40g_sel_i),
		.read_desc_en_i          (read_desc_en_i    ),
		.read_desc_type_i        (read_desc_type_i  ),
		.read_data_o             (read_data_o       ),
		.start_read_i            (start_read_i      ),
		.read_ready_o            (read_ready_o      ),
        
        .read_fifo_wr_en_o       (read_fifo_wr_en_o ),
        .read_fifo_wr_full_i     (read_fifo_wr_full_i),
        
        .read_data_or_desc_sel_o (read_data_or_desc_sel_o),
        .read_desc_fifo_sel_o    (read_desc_fifo_sel_o),
        .read_data_txfifo_sel_o  (read_data_txfifo_sel_o),
        
        .read_data_done_o        (read_data_done),
        .read_desc_done_o        (read_desc_done),
        .read_data_almost_done_o (read_data_almost_done), 
        .read_desc_almost_done_o (read_desc_almost_done), 
        .read_fsm_state_o        (read_fsm_state)
`ifndef VCS_MODEL
		,.ram_2p_cfg_register					(ram_2p_cfg_register),
		.rf_2p_cfg_register						(rf_2p_cfg_register)
`endif
    );
    
endmodule
